﻿using System;
using System.Collections.Generic;
using System.Text;
using SdmxMl.Structure;

namespace SasPlugIn.Table
{
    /// <summary> Holds columns collection for SAS Table creation </summary>
    public class HeaderColumns
    {
        #region Internal Members

        /// <summary> Column list for SAS Table</summary>
        private List<HeaderColumn> columns;

        #endregion

        #region Properties

        /// <summary> Table name in SAS</summary>
        public string Name { get; set; }

        /// <summary> Table prefix in SAS</summary>
        public string Prefix { get; private set; }

        /// <summary>Interface to Columns</summary>
        public IList<HeaderColumn> Columns { get { return this.columns.AsReadOnly(); } }

        #endregion

        #region Constructor


        /// <summary> C'tor with table name only </summary>
        /// <param name="tableName">SAS table name</param>
        public HeaderColumns(string tableName): this(tableName, null) { }

        /// <summary> C'tor with table prefix and table name </summary>
        /// <param name="tableName">SAS table name</param>
        /// <param name="tablePrefix">Prefix before tableName Like: Meta.tableName</param>
        public HeaderColumns(string tableName, string tablePrefix)
        {
            columns = new List<HeaderColumn>();
            Name = tableName;
            Prefix = tablePrefix;
        }

        #endregion

        #region Operator overloading

        // overloads the square brackets to provide array-like access. 
        public HeaderColumn this[string name] 
        {
            get { return this.columns.Find(x => x.Name == name); }
        }
        #endregion

        #region Column adding

        public void Add(HeaderColumn column)
        {
            // Todo check if name already exists

            columns.Add(column);
        }
        #endregion

        #region SAS instructions generation

        /// <summary>
        /// Generates create table instructions according to defined columns
        /// </summary>
        /// <param name="sb">container for string instructions</param>
        public void GenerateCreateTableInstructions(StringBuilder sb)
        {
            string prefixDot = string.IsNullOrEmpty(Prefix) ? string.Empty : Prefix + ".";
  
            sb.Append("drop table ").Append(prefixDot).Append(Name).Append(';').Append(Environment.NewLine); ;
            sb.Append("create table ").Append(prefixDot).Append(Name).Append('(');

            ColumnGenerator colGenerator = new ColumnGenerator();
            foreach (HeaderColumn col in Columns)
            {
                colGenerator.Generate(sb, col.Name, col.TFormat);
                sb.Append(',');
            }
            sb.Remove(sb.Length - 1, 1);
            sb.Append(")").Append(Environment.NewLine).Append(';').Append(Environment.NewLine);
        }

        /// <summary>
        /// Generates values to insert for a data row, according to defined columns
        /// </summary>
        /// <param name="sb">container for string instructions</param>
        /// <param name="rowValues">the datas of the row</param>
        /// <exception cref="System.ArgumentException">Thrown when list count does not match columns count</exception>
        public void GenerateInsertTableInstructions(StringBuilder sb, IList<string> rowValues)
        {
            if (rowValues.Count != Columns.Count)
                throw new ArgumentException("Invalid values count in SAS row Insert. Table = " + Name);

            sb.Append("values(");
            ColumnGenerator colGenerator = new ColumnGenerator();
            int index = 0;
            foreach (HeaderColumn col in Columns)
            {
                colGenerator.InsertValue(sb, rowValues[index++], col.TFormat);
                sb.Append(',');
            }

            sb.Remove(sb.Length - 1, 1);
            sb.Append(")").Append(Environment.NewLine);
        }

        #endregion
    }

    /// <summary>
    /// Class holding information for one SAS table column
    /// </summary>
    public class HeaderColumn
    {
        #region Internal Members

        #endregion

        #region Properties

        /// <summary> Column name in SAS</summary>
        public string Name { get; private set; }

        /// <summary> SDMX Format associated to column</summary>
        public TextFormatType TFormat { get; set; }

        public HeaderCodeList AttachedCodelist { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Simple C'tor with column name, assumes text format and default length
        /// </summary>
        /// <param name="colName"> Column name</param>
         public HeaderColumn(string colName) : this(colName, ColumnGenerator.DEFAULT_STRING_LEN) { }


        /// <summary>C'tor</summary>
        /// <param name="colName">column name</param>
        /// <param name="maxLen">column text max length</param>
        public HeaderColumn(string colName, int maxLen)
        {
            if (maxLen <= 0)
            {
                maxLen = ColumnGenerator.DEFAULT_STRING_LEN;
            }

            // Compose a default string format if none specified
            TextFormatType tft = new TextFormatType();
            tft.maxLength = maxLen.ToString();
            tft.TextType = TextTypeType.String;

            Name = colName;
            TFormat = tft;
        }

        /// <summary>C'tor with specified format</summary>
        /// <param name="colName"> Column name</param>
        /// <param name="tft">SDMX format to associate to column</param>
        public HeaderColumn(string colName, TextFormatType tft)
        {
            Name = colName;
            TFormat = tft;

        }

        #endregion

    }

    /// <summary>
    /// Class holding information for one SAS table column
    /// </summary>
    public class HeaderCodeList
    {
        #region Properties

        /// <summary> Column name in SAS</summary>
        public string Name { get; set; }

        /// <summary>Main codelist associated</summary>
        public CodeListType CltMain { get; private set; }

        /// <summary>Secondary codelist associated</summary>
        public CodeListType CltSecondary { get; private set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Simple C'tor with column name, assumes text format and default length
        /// </summary>
        /// <param name="colName"> Column name</param>
        public HeaderCodeList(CodeListType mainCodelist) : this(mainCodelist, null) { }


        /// <summary>C'tor</summary>
        /// <param name="colName">column name</param>
        /// <param name="maxLen">column text max length</param>
        public HeaderCodeList(CodeListType mainCodelist, CodeListType secondCodelist)
        {
            if (mainCodelist == null)
                throw new ArgumentException();

            CltMain = mainCodelist;
            CltSecondary = secondCodelist;

            // Default Name
            Name = CltMain.Id.StartsWith("CL_") ? CltMain.Id.Substring(3) : CltMain.Id;
        }

        #endregion

        #region Composed codelist access

        /// <summary> Provides codelist to operate in column. </summary>
        /// <remarks> Can be a codelist composed from main and secondary</remarks>
        /// <returns>the codelist to associate to the column</returns>
        public CodeListType GetCodelist()
        {
            CodeListType clt = CltMain;

            // Do we need to merge codes ?
            if (CltSecondary != null)
            {
                clt = new CodeListType();
                clt.Id = CltMain.Id;

                // Merge codes of the two codelists
                clt.CodeList.AddRange(CltMain.CodeList.ToArray());
                clt.CodeList.AddRange(CltSecondary.CodeList.ToArray());
            }

            return clt;
        }
        #endregion

    }


}
